package token

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

// RSA签名实现token
// RAS密钥生成工具链接：http://www.metools.info/code/c80.html
type RsaUser struct {
	UserId   string `json:"user_id"` //根据用户id生成token
	UserName string `json:"user_name"`
}
type RasClaims struct {
	UserId string `json:"user_id"`
	jwt.StandardClaims
}

var (
	resPrivateKey []byte //读取私钥内容
	resPublicKey  []byte //读取公钥内容
	err1, err2    error
)

// 初始化读取秘钥文件内容
func init() {
	resPrivateKey, err1 = ioutil.ReadFile("/home/rx/go/gin-demo/token/pem/privateKey.pem") //路径从GOPATH开始
	resPublicKey, err2 = ioutil.ReadFile("/home/rx/go/gin-demo/token/pem/publicKey.pem")
	if err1 != nil || err2 != nil {
		panic(fmt.Sprintf("读取秘钥文件内容出错：%s,%s", err1, err2))
		return
	}
}
func RsaCreateToken(c *gin.Context) {
	var user RsaUser
	c.Bind(&user) //绑定客户端传来的参数
	fmt.Println("user", user)
	if user.UserId == "" {
		c.JSON(http.StatusBadRequest, "user_id不能为空")
		return
	}
	token, err := _createRsaToken(user)
	if err != nil {
		c.JSON(http.StatusInternalServerError, err)
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "token创建成功",
		"data": gin.H{
			"user_id": user.UserId,
			"token":   token,
		},
	})
}

// 创建token
func _createRsaToken(user RsaUser) (interface{}, error) {
	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(resPrivateKey)
	if err != nil {
		return nil, err
	}
	claims := &RasClaims{
		UserId: user.UserId,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Unix(), //token有效期截止时间，从当前时间往后7天
			Issuer:    "renxing",                                 //发布者
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
	signedString, err := token.SignedString(privateKey)
	return signedString, err
}

// 校验token
func RsaAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		auth := "renxing"
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" || !strings.HasPrefix(tokenString, auth+":") {
			c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "无效的token"})
			c.Abort()
			return
		}
		index := strings.Index(tokenString, auth+":")
		tokenString = tokenString[index+len(auth)+1:]
		claims, err := _rsaParseToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "证书无效"})
			c.Abort()
			return
		}
		claimsValue := claims.(jwt.MapClaims) //断言
		if claimsValue["user_id"] == nil {
			c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
			c.Abort()
			return
		}
		u := RsaUser{}
		c.Bind(&u)
		id := claimsValue["user_id"].(string)
		if u.UserId != id {
			c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户Id不匹配"})
			c.Abort()
			return
		}
		c.Next()
	}
}

// 解析token
func _rsaParseToken(tokenString string) (interface{}, error) {
	pem, err := jwt.ParseRSAPublicKeyFromPEM(resPublicKey)
	if err != nil {
		return nil, err
	}
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
		if _, OK := token.Method.(*jwt.SigningMethodRSA); !OK {
			return nil, fmt.Errorf("解析的方法错误")
		}
		return pem, err
	})
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, err
}
